/**
 * @file spi_dev_simulate.c
 * @author LokLiang (lokliang@163.com)
 * @brief 把 sim_spi_flash 关联到 spi_dev.h 的实现代码
 * @version 0.1
 * @date 2023-06-07
 *
 * @copyright Copyright (c) 2023
 *
 */

#include "drivers/ext/spi_dev.h"
#include "sim_spi_flash.h"
#include "sys_common.h"

static int _dev_init(spi_dev_t spi_dev_hdl, const void *param);
static int _dev_deinit(spi_dev_t spi_dev_hdl);
static int _dev_lock(spi_dev_t spi_dev_hdl);
static void _dev_unlcok(spi_dev_t spi_dev_hdl);
static void _dev_call_enable(spi_dev_t spi_dev_hdl, spi_dev_irq_cb irq, void *arg);
static void _dev_call_disable(spi_dev_t spi_dev_hdl);
static int _dev_cs_set(spi_dev_t spi_dev_hdl);
static int _dev_cs_reset(spi_dev_t spi_dev_hdl);
static int _dev_write(spi_dev_t spi_dev_hdl, const void *src, uint32_t size);
static int _dev_read(spi_dev_t spi_dev_hdl, void *dest, uint32_t size);
static int _dev_is_busy(spi_dev_t spi_dev_hdl);

static spi_dev_cfg_t s_config;

static struct spi_dev const s_device = {
    .api = {
        .init = _dev_init,
        .deinit = _dev_deinit,
        .lock = _dev_lock,
        .unlcok = _dev_unlcok,
        .call_enable = _dev_call_enable,
        .call_disable = _dev_call_disable,
        .cs_set = _dev_cs_set,
        .cs_reset = _dev_cs_reset,
        .write = _dev_write,
        .read = _dev_read,
        .is_busy = _dev_is_busy,
    },
    .cfg = &s_config,
};
OBJ_EXPORT_DEVICE(s_device, "SPI:SIM");

static spi_dev_irq_cb s_irq_cb; // 数据传输完成后的回调函数
static void *s_irq_arg;         // 回调函数附带的参数

static int _dev_init(spi_dev_t spi_dev_hdl, const void *param)
{
    s_irq_cb = NULL;
    return 0;
}

static int _dev_deinit(spi_dev_t spi_dev_hdl)
{
    s_irq_cb = NULL;
    return 0;
}

static void _dev_call_enable(spi_dev_t spi_dev_hdl, spi_dev_irq_cb irq, void *arg)
{
    s_irq_arg = arg;
    s_irq_cb = irq;
}

static void _dev_call_disable(spi_dev_t spi_dev_hdl)
{
    s_irq_cb = NULL;
}

static int _dev_lock(spi_dev_t spi_dev_hdl)
{
    sys_lock_t *lock_hdl = (sys_lock_t *)spi_dev_hdl->cfg;
    sys_lock(lock_hdl, SYS_LOG_FOREVER);
    return 0;
}

static void _dev_unlcok(spi_dev_t spi_dev_hdl)
{
    sys_lock_t *lock_hdl = (sys_lock_t *)spi_dev_hdl->cfg;
    sys_unlock(lock_hdl);
}

static int _dev_cs_set(spi_dev_t spi_dev_hdl)
{
    sim_sf_set_cs();
    return 0;
}

static int _dev_cs_reset(spi_dev_t spi_dev_hdl)
{
    sim_sf_reset_cs();
    return 0;
}

static int _dev_write(spi_dev_t spi_dev_hdl, const void *src, uint32_t size)
{
    sim_sf_spi_write(src, size);
    if (s_irq_cb)
    {
        s_irq_cb(spi_dev_hdl, s_irq_arg);
    }
    return 0;
}

static int _dev_read(spi_dev_t spi_dev_hdl, void *dest, uint32_t size)
{
    sim_sf_spi_read(dest, size);
    if (s_irq_cb)
    {
        s_irq_cb(spi_dev_hdl, s_irq_arg);
    }
    return 0;
}

static int _dev_is_busy(spi_dev_t spi_dev_hdl)
{
    return false;
}
